Store repeating rows in a table field

Best practice
Store a repeating list of rows in a schema by adding a Table field: it defines an Array key and Columns, and each record holds an array of row objects keyed by column title.
Applies to: Schema designerrecords

What you'll see

You want a field that holds a table of rows — a repeating list where each row has several columns, such as a list of attributes, contacts, or line items — instead of a single value. You need to know how to set it up in the schema designer, and exactly what the data must look like inside the document when you fill or generate records programmatically.

What's actually happening

A table field is a repeating group with two sides that must stay in sync: the schema definition and the record data.

Schema side. In the schema document the field is an entry in Document.Fields[] with ObjectVariant: "Table". Unlike a normal field it has no Name property — instead it carries:

  • Array — the name of the property the rows are stored under in each record (e.g. "Attributter"). This is how a table field is identified.
  • Columns — an array of { "Title": "…" }. The column Title becomes the property key on every row. There is no separate ASCII-key / label split like regular fields (Name vs Field); Title does both, so keep it a clean key (Attributt, not a sentence).
  • Rows — a one-row scaffold with one empty Cells[] entry per column. Empty Cells[].Fields[] means a plain text column; typed columns (dropdown, number) are defined by placing a field definition inside a cell.

The designer also generates matching markup in schema.html: a <table class="table-grid"> with a <thead> of column titles and a <tbody data-array="…"> whose template cells carry data-func="input" data-name="<ColumnTitle>".

Record side. In each document, Document gets a property named exactly the schema’s Array value, holding an array of row objects. Every row has one key per column (the column Title) plus a generated ROWID. A sibling <Array>_type property is present alongside it.

What to do

1. Add the table field in the schema designer. Add a Table (grid) field, give it an array name, and define its columns. This is a one-time visual step — it writes both the Fields[] entry and the schema.html form for you, kept in sync.

2. Name columns as keys, not sentences. The column Title becomes the JSON key on every row, so use Attributt, Type — not “What the attribute is called”.

3. Fill data programmatically as an array of objects. Add a property to Document named exactly the array name. Each row object holds one key per column Title plus a ROWID (uuid-style). Include the sibling <name>_type.

// schema Fields[] entry (Table field)
{
  "ObjectVariant": "Table",
  "Array": "Attributter",
  "Columns": [ { "Title": "Attributt" }, { "Title": "Type" } ],
  "Columns_type": "Columns",
  "Rows": [ { "Cells": [ { "Fields": [], "Fields_type": "Fields" },
                        { "Fields": [], "Fields_type": "Fields" } ],
            "Cells_type": "Cells" } ],
  "Rows_type": "Rows"
}

// record Document — same key as Array
"Attributter": [
  { "Attributt": "E-postadresse", "Type": "Tekst", "ROWID": "102f422e-…" },
  { "Attributt": "Navn",          "Type": "Tekst", "ROWID": "2bff8e62-…" }
],
"Attributter_type": "Table"

4. Read the rows in a template. In a .hash display file, loop over the array and use the column titles as keys:

#for(let r of Attributter){#
  <tr><td>#r.Attributt#</td><td>#r.Type#</td></tr>
#}#

5. The schema definition (Fields[]) is the source of truth — schema.html is a generated artifact. The server rebuilds schema.html from Fields[] with no designer round-trip needed. Add a table field to Fields[] by hand-editing the schema document over the mapped drive, read the document back, and the generated form is already there — <tbody data-array="…"> with a template cell per column, and the panel markup for its chapter. So hand-editing Fields[] is the whole change: there is no second step to refresh the form, and no window in which the Admin form still shows the old columns. What you must not edit is schema.html itself — it is regenerated from the field definitions, so anything written there is discarded.